# -*- coding: utf-8 -*-
"""
投资组合模块 - API视图定义

本文件定义了测试DEMO中投资组合相关的所有API视图，包括：

1. 投资组合管理API
   - PortfolioListCreateView: 获取用户投资组合列表和创建新组合
   - PortfolioDetailView: 获取、更新、删除投资组合详情
   - 支持用户权限验证和数据隔离

2. 投资组合持仓管理API
   - PortfolioHoldingListView: 获取投资组合的持仓列表
   - 显示每个产品的持仓详情和盈亏情况
   - 支持按组合ID过滤持仓数据

3. 交易记录管理API
   - TransactionListCreateView: 获取交易记录列表和创建新交易
   - 记录买入、卖出、分红等交易活动
   - 按时间倒序排列，便于查看最新交易

4. 止损设置管理API
   - StopLossSettingListCreateView: 获取和创建止损设置
   - 支持固定比例、移动止损、技术指标等策略
   - 为投资组合提供风险控制功能

5. 资产配置建议API
   - asset_allocation: 基于风险等级提供资产配置建议
   - 支持5个风险等级（保守、稳健、平衡、成长、激进）
   - 提供4:3:2:1配置策略的具体分配方案
   - 计算各类型产品的投资金额

6. 投资组合再平衡API
   - rebalance_portfolio: 投资组合再平衡建议
   - 分析当前持仓与目标配置的偏差
   - 提供调仓建议和具体操作方案

7. 投资组合分析API
   - portfolio_performance: 投资组合业绩分析
   - portfolio_risk_analysis: 投资组合风险分析
   - 提供收益率、波动率、夏普比率等指标
   - 支持历史业绩和风险评估

所有API都要求用户认证，确保数据安全和隐私保护。
视图集成了产品推荐引擎，提供智能化的投资建议。
支持完整的错误处理和日志记录机制。

Author: zhaozeliang
Date: 2025-09-06
"""

from rest_framework import generics, status, permissions
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from django.db.models import Sum, F, Q
from decimal import Decimal
from datetime import datetime, timedelta
from .models import Portfolio, PortfolioHolding, StopLossSetting, Transaction
from .serializers import (
    PortfolioSerializer, PortfolioDetailSerializer, PortfolioCreateSerializer,
    PortfolioHoldingSerializer, StopLossSettingSerializer, TransactionSerializer,
    AssetAllocationSerializer, RebalanceSerializer
)
from .recommendation_engine import ProductRecommendationEngine
from products.models import Product
from users.models import User
import logging

logger = logging.getLogger(__name__)


class PortfolioListCreateView(generics.ListCreateAPIView):
    """投资组合列表和创建视图"""
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return Portfolio.objects.filter(user=self.request.user)
    
    def get_serializer_class(self):
        if self.request.method == 'POST':
            return PortfolioCreateSerializer
        return PortfolioSerializer
    
    def perform_create(self, serializer):
        serializer.save(user=self.request.user)


class PortfolioDetailView(generics.RetrieveUpdateDestroyAPIView):
    """投资组合详情视图"""
    serializer_class = PortfolioDetailSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        return Portfolio.objects.filter(user=self.request.user)


class PortfolioHoldingListView(generics.ListAPIView):
    """投资组合持仓列表视图"""
    serializer_class = PortfolioHoldingSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        portfolio_id = self.kwargs['portfolio_id']
        portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=self.request.user)
        return PortfolioHolding.objects.filter(portfolio=portfolio)


class TransactionListCreateView(generics.ListCreateAPIView):
    """交易记录列表和创建视图"""
    serializer_class = TransactionSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        portfolio_id = self.kwargs['portfolio_id']
        portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=self.request.user)
        return Transaction.objects.filter(portfolio=portfolio).order_by('-created_at')
    
    def perform_create(self, serializer):
        portfolio_id = self.kwargs['portfolio_id']
        portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=self.request.user)
        serializer.save(portfolio=portfolio)


class StopLossSettingListCreateView(generics.ListCreateAPIView):
    """止损设置列表和创建视图"""
    serializer_class = StopLossSettingSerializer
    permission_classes = [permissions.IsAuthenticated]
    
    def get_queryset(self):
        portfolio_id = self.kwargs['portfolio_id']
        portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=self.request.user)
        return StopLossSetting.objects.filter(portfolio=portfolio)
    
    def perform_create(self, serializer):
        portfolio_id = self.kwargs['portfolio_id']
        portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=self.request.user)
        serializer.save(portfolio=portfolio)


@api_view(['POST'])
@permission_classes([permissions.AllowAny])
def asset_allocation(request):
    """资产配置建议"""
    try:
        # 获取请求参数
        risk_level = request.data.get('risk_level', 3)  # 默认平衡型
        investment_amount = Decimal(str(request.data.get('investment_amount', 100000)))  # 默认10万
        
        # 验证风险等级
        if risk_level not in [1, 2, 3, 4, 5]:
            return Response({
                'error': '风险等级必须在1-5之间',
                'risk_levels': {
                    1: '保守型',
                    2: '稳健型', 
                    3: '平衡型',
                    4: '成长型',
                    5: '激进型'
                }
            }, status=status.HTTP_400_BAD_REQUEST)
        
        # 使用推荐引擎
        recommendation_engine = ProductRecommendationEngine()
        
        # 获取配置策略
        allocation_strategies = {
            1: {'stock': 0.1, 'bond': 0.4, 'fund': 0.3, 'cash': 0.2},  # 保守型
            2: {'stock': 0.2, 'bond': 0.3, 'fund': 0.3, 'cash': 0.2},  # 稳健型
            3: {'stock': 0.3, 'bond': 0.3, 'fund': 0.2, 'cash': 0.2},  # 平衡型
            4: {'stock': 0.4, 'bond': 0.2, 'fund': 0.3, 'cash': 0.1},  # 成长型
            5: {'stock': 0.5, 'bond': 0.1, 'fund': 0.3, 'cash': 0.1},  # 激进型
        }
        
        strategy = allocation_strategies[risk_level]
        
        # 计算各类资产配置金额
        allocation_result = {}
        for asset_type, ratio in strategy.items():
            amount = investment_amount * Decimal(str(ratio))
            allocation_result[asset_type] = {
                'ratio': ratio,
                'amount': float(amount),
                'percentage': f"{ratio * 100:.1f}%"
            }
        
        # 获取智能推荐产品
        recommended_products = recommendation_engine.get_recommended_products(
            risk_level=risk_level,
            total_amount=investment_amount
        )
        
        # 风险等级描述
        risk_descriptions = {
            1: '保守型：追求资本保值，风险承受能力较低',
            2: '稳健型：追求稳定收益，风险承受能力一般',
            3: '平衡型：平衡风险与收益，风险承受能力中等',
            4: '成长型：追求较高收益，风险承受能力较强',
            5: '激进型：追求高收益，风险承受能力很强'
        }
        
        return Response({
            'risk_level': risk_level,
            'risk_description': risk_descriptions[risk_level],
            'investment_amount': float(investment_amount),
            'allocation_strategy': allocation_result,
            'recommended_products': recommended_products,
            'strategy_description': '基于现代投资组合理论的4:3:2:1配置策略，根据风险偏好动态调整各类资产比例',
            'rebalance_suggestion': '建议每季度检查并重新平衡投资组合，确保资产配置符合目标比例'
        })
        
    except ValueError as e:
        return Response({
            'error': f'参数格式错误: {str(e)}'
        }, status=status.HTTP_400_BAD_REQUEST)
    except Exception as e:
        logger.error(f"资产配置建议生成失败: {e}")
        return Response({
            'error': '服务器内部错误，请稍后重试'
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


@api_view(['POST'])
@permission_classes([permissions.IsAuthenticated])
def rebalance_portfolio(request):
    """投资组合再平衡"""
    serializer = RebalanceSerializer(data=request.data, context={'request': request})
    if serializer.is_valid():
        portfolio_id = serializer.validated_data['portfolio_id']
        rebalance_type = serializer.validated_data['rebalance_type']
        
        portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=request.user)
        
        # 获取当前持仓
        holdings = PortfolioHolding.objects.filter(portfolio=portfolio)
        
        # 计算当前总价值
        total_value = sum(holding.quantity * holding.average_price for holding in holdings)
        
        # 计算目标配置
        target_allocation = {
            'stock': total_value * Decimal('0.4'),
            'bond': total_value * Decimal('0.3'),
            'fund': total_value * Decimal('0.2'),
            'cash': total_value * Decimal('0.1'),
        }
        
        # 计算当前配置
        current_allocation = {}
        for holding in holdings:
            category = holding.product.category.name.lower()
            current_value = holding.quantity * holding.average_price
            current_allocation[category] = current_allocation.get(category, Decimal('0')) + current_value
        
        # 计算需要调整的金额
        adjustments = []
        for category, target_value in target_allocation.items():
            current_value = current_allocation.get(category, Decimal('0'))
            difference = target_value - current_value
            if abs(difference) > total_value * Decimal('0.05'):  # 5%阈值
                adjustments.append({
                    'category': category,
                    'current_value': current_value,
                    'target_value': target_value,
                    'adjustment': difference,
                    'action': 'buy' if difference > 0 else 'sell'
                })
        
        return Response({
            'portfolio_id': portfolio_id,
            'total_value': total_value,
            'current_allocation': current_allocation,
            'target_allocation': target_allocation,
            'adjustments': adjustments,
            'rebalance_needed': len(adjustments) > 0
        })
    
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def portfolio_performance(request, portfolio_id):
    """投资组合业绩分析"""
    portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=request.user)
    
    # 获取时间范围
    days = int(request.GET.get('days', 30))
    start_date = datetime.now() - timedelta(days=days)
    
    # 获取交易记录
    transactions = Transaction.objects.filter(
        portfolio=portfolio,
        created_at__gte=start_date
    ).order_by('created_at')
    
    # 计算业绩指标
    total_investment = transactions.filter(transaction_type='buy').aggregate(
        total=Sum('amount')
    )['total'] or Decimal('0')
    
    total_redemption = transactions.filter(transaction_type='sell').aggregate(
        total=Sum('amount')
    )['total'] or Decimal('0')
    
    # 获取当前持仓价值
    holdings = PortfolioHolding.objects.filter(portfolio=portfolio)
    current_value = sum(holding.quantity * holding.average_price for holding in holdings)
    
    # 计算收益率
    net_investment = total_investment - total_redemption
    if net_investment > 0:
        total_return = (current_value - net_investment) / net_investment
    else:
        total_return = Decimal('0')
    
    return Response({
        'portfolio_id': portfolio_id,
        'period_days': days,
        'total_investment': total_investment,
        'total_redemption': total_redemption,
        'current_value': current_value,
        'total_return': total_return,
        'absolute_return': current_value - net_investment,
        'transaction_count': transactions.count(),
        'holdings_count': holdings.count()
    })


@api_view(['GET'])
@permission_classes([permissions.IsAuthenticated])
def portfolio_risk_analysis(request, portfolio_id):
    """投资组合风险分析"""
    portfolio = get_object_or_404(Portfolio, id=portfolio_id, user=request.user)
    
    holdings = PortfolioHolding.objects.filter(portfolio=portfolio)
    
    # 计算集中度风险
    total_value = sum(holding.quantity * holding.average_price for holding in holdings)
    concentration_risk = []
    
    for holding in holdings:
        holding_value = holding.quantity * holding.average_price
        weight = holding_value / total_value if total_value > 0 else 0
        concentration_risk.append({
            'product_name': holding.product.name,
            'weight': weight,
            'risk_level': 'high' if weight > 0.3 else 'medium' if weight > 0.15 else 'low'
        })
    
    # 计算行业分布
    industry_distribution = {}
    for holding in holdings:
        industry = holding.product.category.name
        holding_value = holding.quantity * holding.average_price
        industry_distribution[industry] = industry_distribution.get(industry, Decimal('0')) + holding_value
    
    # 风险评级
    risk_score = 0
    for holding in holdings:
        holding_value = holding.quantity * holding.average_price
        weight = holding_value / total_value if total_value > 0 else 0
        product_risk = getattr(holding.product, 'risk_level', 3)  # 默认风险等级3
        risk_score += weight * product_risk
    
    return Response({
        'portfolio_id': portfolio_id,
        'total_value': total_value,
        'concentration_risk': concentration_risk,
        'industry_distribution': industry_distribution,
        'overall_risk_score': risk_score,
        'risk_level': 'high' if risk_score > 4 else 'medium' if risk_score > 2 else 'low'
    })
